package org.mcjug.locationmailer.oauth.tokens;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import org.mcjug.locationmailer.util.Constants;
import org.mcjug.locationmailer.util.EmailUtil;
import org.mcjug.locationmailer.util.ExceptionUtil;
import org.mcjug.locationmailer.util.RunnableWithException;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.AsyncTask;
//import android.util.//Log;

public class RetrieveAccessTokenTask extends AsyncTask<Uri, Void, Void> {
    private final String TAG = getClass().getSimpleName();

    private Context context;
    private OAuthProvider provider;
    private OAuthConsumer consumer;
    private SharedPreferences prefs;
    private RunnableWithException runAfterWork;
    private RunnableWithException cleanupAfterException = new RunnableWithException() {

        @Override
        public void run() throws Throwable {
            cancel(true);
            if (prefs != null) {
                final Editor edit = prefs.edit();
                edit.remove(OAuth.OAUTH_TOKEN);
                edit.remove(OAuth.OAUTH_TOKEN_SECRET);
                edit.remove(Constants.PREFS_SENDER_EMAIL_ADDRESS);
                edit.commit();
            }
        }
    };

    public RetrieveAccessTokenTask(Context context, OAuthConsumer consumer, OAuthProvider provider,
            SharedPreferences prefs, RunnableWithException runAfterWork) {
        //Log.d(TAG, "RetrieveAccessTokenTask constructor");
        this.context = context;
        this.consumer = consumer;
        this.provider = provider;
        this.prefs = prefs;
        this.runAfterWork = runAfterWork;
    }

    /**
     * Retrieve the oauth_verifier, and store the oauth and oauth_token_secret for future API calls.
     */
    protected Void doInBackground(Uri... params) {
        boolean commitedEdit = false;
        try {
            //Log.d(TAG, "Enter method doInBackground()");
            final Uri uri = params[0];

            final String oauth_verifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);

            provider.retrieveAccessToken(consumer, oauth_verifier);

            final Editor edit = prefs.edit();
            edit.putString(OAuth.OAUTH_TOKEN, consumer.getToken());
            edit.putString(OAuth.OAUTH_TOKEN_SECRET, consumer.getTokenSecret());

            //Log.i(TAG, "OAuth - Access Token Retrieved");

            retrieveEmailAddress(edit);
            //Log.d(TAG, "Finished call retrieveEmailAddress");
            commitedEdit = edit.commit();
            //Log.d(TAG, "Saved email address to preferences, editCommited is: " + commitedEdit);
        } catch (Throwable e) {
            if (e.getMessage().contains("400") && e.getMessage().toUpperCase().contains("BAD")
                    && e.getMessage().toUpperCase().contains("REQUEST")) {
                // if user denied access there should be a 400 bad request in the message.
            } else {
                // otherwise its an unexpected exception, we need to show the exception dia//Log
                //Log.e(TAG, "RetrieveAccessTokenTask doInBackground Error", e);
                ExceptionUtil.exceptAway(context, e, "RetrieveAccessTokenTask doInBackground Error:",
                        cleanupAfterException);
            }
        }
        try {
            runAfterWork.run();
        } catch (Throwable e) {
            //Log.e(TAG, "RetrieveAccessTokenTask doInBackground Error", e);
            if (commitedEdit) {
                ExceptionUtil.exceptAway(context, e, "RetrieveAccessTokenTask doInBackground Error:", null);
            } else {
                ExceptionUtil.exceptAway(context, e, "RetrieveAccessTokenTask doInBackground Error:",
                        cleanupAfterException);
            }

        }

        return null;
    }

    private void retrieveEmailAddress(Editor edit) throws JSONException, Throwable {
        // request
        String jsonResponse = urlToString("https://www.googleapis.com/userinfo/email?alt=json");
        //Log.d(TAG, "Got JSon response " + jsonResponse);
        if (jsonResponse != null) {
            JSONObject jsonObject = new JSONObject(jsonResponse);

            JSONObject data = jsonObject.getJSONObject("data");
            String emailAddress = data.getString("email");
            //Log.d(TAG, "Retrieved email address, it is: " + emailAddress);
            // save to pref
            edit.putString(Constants.PREFS_SENDER_EMAIL_ADDRESS, emailAddress);
            
            // Save in email address list
            edit.putString(EmailUtil.EMAIL_ADDRESS, emailAddress);
            edit.putString(EmailUtil.EMAIL_ADDRESS_STATE,  Boolean.toString(true));
         }
    }

    private String urlToString(String url) throws Throwable {
        HttpClient httpClient = new DefaultHttpClient();
        try {
            HttpGet request = new HttpGet(url);

            // sign the request
            consumer.sign(request);

            HttpResponse response = httpClient.execute(request);
            HttpEntity entity = response.getEntity();

            if (entity != null) {
                InputStream instream = entity.getContent();
                try {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(instream));

                    StringBuilder builder = new StringBuilder();
                    String line = null;
                    while ((line = reader.readLine()) != null) {
                        builder.append(line);
                    }

                    return builder.toString();
                } catch (RuntimeException e) {
                    //Log.e(TAG, "OAuth - retrieve email address error; RuntimeException on url=" + url, e);
                    request.abort();
                    throw new RuntimeException(e);
                } finally {
                    // Closing the input stream will trigger connection release
                    instream.close();
                }
            }
        } finally {
            // When HttpClient instance is no longer needed,
            // shut down the connection manager to ensure
            // immediate deallocation of all system resources
            httpClient.getConnectionManager().shutdown();
        }

        return null;
    }

}
